use core::{
    ffi::{c_char, c_void},
    ptr::null_mut,
    usize,
};

use crate::{
    c::{
        osRtxThread_t, osThreadAttr_t, osThreadId_t, osThreadJoin, osThreadNew
    },
    utils::Store,
};

const CB_SIZE: usize = size_of::<osRtxThread_t>();

pub struct Thread<const STACK_SIZE: usize, const ATTRS: u32, const PRIORITY: i32> {
    stack_mem: Store<STACK_SIZE>,
    cb_mem: Store<CB_SIZE>,
    id: osThreadId_t,
}

impl<const STACK_SIZE: usize, const ATTRS: u32, const PRIORITY: i32>
    Thread<STACK_SIZE, ATTRS, PRIORITY>
{
    pub const fn const_new() -> Self {
        Self {
            stack_mem: Store::const_new(),
            cb_mem: Store::const_new(),
            id: null_mut(),
        }
    }

    pub fn start(
        &mut self,
        name: &str,
        task_fn: extern "C" fn(_arg: *mut c_void),
        arg: *mut c_void,
    ) {
        let attr = osThreadAttr_t {
            name: name.as_ptr() as *const c_char,
            attr_bits: ATTRS,
            cb_mem: self.cb_mem.c_ptr(),
            cb_size: CB_SIZE as u32,
            stack_mem: self.stack_mem.c_ptr(),
            stack_size: STACK_SIZE as u32,
            priority: PRIORITY,
            tz_module: 0,
            reserved: 0,
        };
        unsafe {
            self.id = osThreadNew(Some(task_fn), arg, &attr);
        }
        debug_assert!(self.id != null_mut(), "thread start fail");
    }

    pub fn join(&self) {
        unsafe { osThreadJoin(self.id); }
    }


}
